#include <iostream>
#include <cstdio>
#include <string>
#include <pthread.h>
#include <unistd.h>
using namespace std;

int tickets = 1000;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition_variable = PTHREAD_COND_INITIALIZER;

void* start_routine(void* args) {
    string name(static_cast<const char*>(args));

    while (true) {
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&condition_variable, &mutex); // 这里传入mutex的意义是为了避免死锁，当线程被条件变量挂起时，会释放它所拥有的锁

        cout << name << " -> " << tickets << endl;
        --tickets;
        pthread_mutex_unlock(&mutex);
    }
}

int main() {
    pthread_t threads[5] = {};

    for (int i = 0; i < 5; ++i) {
        // char buffer[128] = {};
        // buffer不能为局部变量，因为start_routine会用到buffer，
        // 但buffer的作用域只在for循环中，我们并不知道哪个线程先被调度
        // 万一是主线程先被调度的话，buffer就会被释放，新线程调用时就会出现非法访问
        // 这里严格意义上是不行的，因为最后没有手动delete[]，尽管会随着进程的结束而被释放
        // 但是仍存在内存泄漏的风险，最后封装一个类来充当线程的上下文，把上下文作为参数传入
        char* buffer = new char[128]; 
        snprintf(buffer, sizeof buffer, "thread[%d]", i + 1);
        pthread_create(threads + 1, nullptr, start_routine, (void*)buffer);
    }

    while (true) {
        usleep(500000); // 0.5s
        pthread_cond_broadcast(&condition_variable);
        cout << "main thread wake up all threads ..." << endl;
    }

    for (auto& thread : threads) {
        pthread_join(thread, nullptr);
    }
    return 0;
}